개요
Timefit 예약 관리 시스템의 사용자 인증 및 권한 관리를 위한 API입니다. 업체 사용자 회원가입/로그인, 고객 OAuth 로그인, JWT 토큰 관리 기능을 제공합니다.
API 목록
구분 | API 명 | 설명 |
---|---|---|
업체 인증 | 업체 회원가입 | 업체 사용자 회원가입 처리 |
업체 인증 | 업체 로그인 | 업체 사용자 로그인 처리 |
고객 인증 | 고객 OAuth 로그인 | 고객 소셜 로그인 처리 (Google, Kakao) |
토큰 관리 | 토큰 갱신 | JWT 액세스 토큰 갱신 |
토큰 관리 | 로그아웃 | 토큰 무효화 처리 |
시스템 | 헬스 체크 | 서비스 상태 확인 |
1. 업체 회원가입
업체 사용자의 회원가입을 처리합니다.
Request
Request Syntax
bash
curl -X POST https://{SERVER_URL}/api/business/auth/signup \\
-H "Content-Type: application/json" \\
-d '{
"email": "business@example.com",
"password": "Password123!",
"name": "홍길동",
"phoneNumber": "01012345678",
"businessName": "홍길동 미용실",
"businessType": "미용실",
"businessNumber": "123-45-67890",
"address": "서울시 강남구 테헤란로 123",
"contactPhone": "0212345678",
"description": "깔끔하고 세련된 미용실입니다"
}'
메서드 | 요청 URL |
---|---|
POST | https://{SERVER_URL}/api/business/auth/signup |
Request Header
파라미터 | 타입 | 필수여부 | 설명 |
---|---|---|---|
Content-Type | String | 필수 | application/json |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
string | Y | 업체 이메일 주소 | business@example.com | 이메일 형식 | |
password | string | Y | 비밀번호 | Password123! | 8자 이상, 대소문자+숫자+특수문자 |
name | string | Y | 업체 담당자 이름 | 홍길동 | 2자 이상 |
phoneNumber | string | Y | 업체 담당자 연락처 | 01012345678 | 01X-XXXX-XXXX 형식 |
businessName | string | Y | 상호명 | 홍길동 미용실 | 2자 이상 |
businessType | string | N | 업종 | 미용실 | - |
businessNumber | string | Y | 사업자번호 | 123-45-67890 | XXX-XX-XXXXX 형식 |
address | string | N | 사업장 주소 | 서울시 강남구... | - |
contactPhone | string | N | 업체 대표 연락처 | 0212345678 | - |
description | string | N | 업체 설명 | 깔끔하고... | 1000자 이하 |
Response
Response Syntax (201 Created)
json
{
"success": true,
"message": "업체 회원가입이 완료되었습니다",
"data": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"email": "business@example.com",
"name": "홍길동",
"phoneNumber": "01012345678",
"role": "BUSINESS",
"profileImageUrl": null,
"businesses": [
{
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"businessType": "미용실",
"businessNumber": "123-45-67890",
"address": "서울시 강남구 테헤란로 123",
"contactPhone": "0212345678",
"description": "깔끔하고 세련된 미용실입니다",
"logoUrl": null,
"role": "OWNER",
"joinedAt": "2024-06-07T12:30:00Z",
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
}
],
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"createdAt": "2024-06-07T12:30:00Z",
"lastLoginAt": "2024-06-07T12:30:00Z"
}
}
Response Elements
필드 | 타입 | 필수여부 | 설명 |
---|---|---|---|
userId | string | 필수 | 사용자 고유 ID (UUID) |
string | 필수 | 사용자 이메일 | |
name | string | 필수 | 사용자 이름 |
phoneNumber | string | 선택 | 사용자 연락처 |
role | string | 필수 | 사용자 역할 (BUSINESS) |
profileImageUrl | string | 선택 | 프로필 이미지 URL |
businesses | array | 필수 | 사용자가 속한 비즈니스 목록 |
businesses[].businessId | string | 필수 | 비즈니스 고유 ID |
businesses[].businessName | string | 필수 | 상호명 |
businesses[].businessType | string | 선택 | 업종 |
businesses[].businessNumber | string | 필수 | 사업자번호 |
businesses[].address | string | 선택 | 사업장 주소 |
businesses[].contactPhone | string | 선택 | 업체 연락처 |
businesses[].description | string | 선택 | 업체 설명 |
businesses[].logoUrl | string | 선택 | 업체 로고 URL |
businesses[].role | string | 필수 | 비즈니스 내 역할 (OWNER, MANAGER, MEMBER) |
businesses[].joinedAt | string | 필수 | 비즈니스 참여 일시 |
businesses[].createdAt | string | 필수 | 비즈니스 생성 일시 |
businesses[].updatedAt | string | 필수 | 비즈니스 수정 일시 |
accessToken | string | 필수 | JWT 액세스 토큰 |
refreshToken | string | 필수 | JWT 리프레시 토큰 |
tokenType | string | 필수 | 토큰 타입 (Bearer) |
expiresIn | integer | 필수 | 토큰 만료 시간 (초) |
createdAt | string | 필수 | 사용자 생성 일시 |
lastLoginAt | string | 필수 | 마지막 로그인 일시 |
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
EMAIL_ALREADY_EXISTS | 409 | "이미 존재하는 이메일입니다" | 이메일 중복 |
BUSINESS_NUMBER_ALREADY_EXISTS | 409 | "이미 등록된 사업자번호입니다" | 사업자번호 중복 |
VALIDATION_ERROR | 400 | "입력값이 올바르지 않습니다" | 필드 검증 실패 |
INTERNAL_SERVER_ERROR | 500 | "서버 내부 오류가 발생했습니다" | 서버 처리 오류 |
2. 업체 로그인
업체 사용자의 로그인을 처리합니다.
Request
Request Syntax
bash
curl -X POST https://{SERVER_URL}/api/business/auth/signin \\
-H "Content-Type: application/json" \\
-d '{
"email": "business@example.com",
"password": "Password123!"
}'
메서드 | 요청 URL |
---|---|
POST | https://{SERVER_URL}/api/business/auth/signin |
Request Header
파라미터 | 타입 | 필수여부 | 설명 |
---|---|---|---|
Content-Type | String | 필수 | application/json |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
string | Y | 업체 이메일 주소 | business@example.com | |
password | string | Y | 비밀번호 | Password123! |
Response
Response Syntax (200 OK)
json
{
"success": true,
"message": "로그인이 완료되었습니다",
"data": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"email": "business@example.com",
"name": "홍길동",
"phoneNumber": "01012345678",
"role": "BUSINESS",
"profileImageUrl": null,
"businesses": [
{
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"businessType": "미용실",
"businessNumber": "123-45-67890",
"address": "서울시 강남구 테헤란로 123",
"contactPhone": "0212345678",
"description": "깔끔하고 세련된 미용실입니다",
"logoUrl": null,
"role": "OWNER",
"joinedAt": "2024-06-01T12:30:00Z",
"createdAt": "2024-06-01T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
},
{
"businessId": "770e8400-e29b-41d4-a716-446655440002",
"businessName": "홍길동 네일샵",
"businessType": "네일샵",
"businessNumber": "987-65-43210",
"address": "서울시 강남구 테헤란로 456",
"contactPhone": "0287654321",
"description": "고급스러운 네일아트 전문샵입니다",
"logoUrl": "<https://example.com/logo2.jpg>",
"role": "MANAGER",
"joinedAt": "2024-06-05T14:20:00Z",
"createdAt": "2024-06-03T09:15:00Z",
"updatedAt": "2024-06-06T16:45:00Z"
}
],
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"createdAt": "2024-05-01T09:00:00Z",
"lastLoginAt": "2024-06-07T12:30:00Z"
}
}
Response Elements
응답 구조는 업체 회원가입과 동일하며, 차이점은 다음과 같습니다:
- 사용자가 여러 비즈니스에 속할 수 있으므로
businesses
배열에 여러 항목이 포함될 수 있습니다 - 각 비즈니스별로 다른
role
을 가질 수 있습니다 (OWNER, MANAGER, MEMBER)
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
INVALID_CREDENTIALS | 401 | "이메일 또는 비밀번호가 올바르지 않습니다" | 로그인 정보 불일치 |
USER_NOT_FOUND | 404 | "사용자를 찾을 수 없습니다" | 존재하지 않는 이메일 |
VALIDATION_ERROR | 400 | "입력값이 올바르지 않습니다" | 필드 검증 실패 |
3. 고객 OAuth 로그인
고객의 소셜 로그인(Google, Kakao)을 처리합니다.
Request
Request Syntax
bash
curl -X POST https://{SERVER_URL}/api/customer/auth/oauth \\
-H "Content-Type: application/json" \\
-d '{
"provider": "GOOGLE",
"accessToken": "ya29.a0AfH6SMC...",
"oauthId": "1234567890"
}'
메서드 | 요청 URL |
---|---|
POST | https://{SERVER_URL}/api/customer/auth/oauth |
Request Header
파라미터 | 타입 | 필수여부 | 설명 |
---|---|---|---|
Content-Type | String | 필수 | application/json |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
provider | string | Y | OAuth 제공자 | GOOGLE, KAKAO |
accessToken | string | Y | OAuth 제공자에서 받은 액세스 토큰 | ya29.a0AfH6SMC... |
oauthId | string | Y | OAuth 제공자의 사용자 고유 ID | 1234567890 |
Response
Response Syntax (200 OK / 201 Created)
json
{
"success": true,
"message": "로그인이 완료되었습니다",
"data": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"email": "customer@gmail.com",
"name": "김고객",
"phoneNumber": "01098765432",
"role": "USER",
"profileImageUrl": "https://...",
"oauthProvider": "GOOGLE",
"oauthId": "1234567890",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"isFirstLogin": false,
"createdAt": "2024-06-07T12:30:00Z",
"lastLoginAt": "2024-06-07T12:30:00Z"
}
}
Response Elements
필드 | 타입 | 필수여부 | 설명 |
---|---|---|---|
isFirstLogin | boolean | 필수 | 최초 로그인 여부 |
oauthProvider | string | 필수 | OAuth 제공자 |
oauthId | string | 필수 | OAuth ID |
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
OAUTH_PROVIDER_ERROR | 400 | "OAuth 인증 중 오류가 발생했습니다" | OAuth 토큰 검증 실패 |
INVALID_CREDENTIALS | 401 | "유효하지 않은 인증 정보입니다" | 잘못된 토큰 또는 ID |
VALIDATION_ERROR | 400 | "입력값이 올바르지 않습니다" | 필드 검증 실패 |
4. 토큰 갱신
JWT 액세스 토큰을 갱신합니다.
Request
Request Syntax
bash
curl -X POST https://{SERVER_URL}/api/auth/refresh \\
-H "Content-Type: application/json" \\
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
메서드 | 요청 URL |
---|---|
POST | https://{SERVER_URL}/api/auth/refresh |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
refreshToken | string | Y | 리프레시 토큰 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
Response
Response Syntax (200 OK)
json
{
"success": true,
"message": "토큰이 갱신되었습니다",
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600
}
}
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
TOKEN_EXPIRED | 401 | "리프레시 토큰이 만료되었습니다" | 리프레시 토큰 만료 |
TOKEN_INVALID | 401 | "유효하지 않은 토큰입니다" | 토큰 검증 실패 |
5. 로그아웃
사용자 로그아웃 및 토큰 무효화를 처리합니다.
Request
Request Syntax
bash
curl -X POST https://{SERVER_URL}/api/auth/logout \\
-H "Authorization: Bearer {ACCESS_TOKEN}" \\
-H "Content-Type: application/json" \\
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
메서드 | 요청 URL |
---|---|
POST | https://{SERVER_URL}/api/auth/logout |
Request Header
파라미터 | 타입 | 필수여부 | 설명 |
---|---|---|---|
Authorization | String | 필수 | Bearer |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
refreshToken | string | Y | 리프레시 토큰 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
Response
Response Syntax (200 OK)
json
{
"success": true,
"message": "로그아웃이 완료되었습니다",
"data": {
"loggedOutAt": "2024-06-07T12:30:00Z"
}
}
인증 토큰 사용법
토큰 생명주기
- Access Token: 1시간 (3600초)
- Refresh Token: 7일 (604800초)
토큰 갱신 플로우
- API 요청 시 401 Unauthorized 응답
- Refresh Token으로 새 Access Token 발급
- 새 Access Token으로 API 재요청
- Refresh Token도 만료된 경우 재로그인 필요
JWT 토큰 Payload 구조
json
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"email": "business@example.com",
"role": "BUSINESS",
"businessIds": ["660e8400-e29b-41d4-a716-446655440001"],
"iat": 1640995200,
"exp": 1641081600
}
새로 추가된 필드:
businessIds
: 사용자가 속한 비즈니스 ID 목록 (권한 체크용)